package com.jiangxjsy.authorization.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.jiangxjsy.authorization.client.AdminUserClient;
import com.jiangxjsy.authorization.property.JwtProperty;
import com.jiangxjsy.authorization.service.LoginService;
import com.jiangxjsy.authorization.support.LoginSupport;
import com.jiangxjsy.authorization.support.PermissionSupport;
import com.jiangxjsy.core.constant.AdminCacheKey;
import com.jiangxjsy.core.constant.BasicConstant;
import com.jiangxjsy.core.constant.CrmCacheKey;
import com.jiangxjsy.core.constant.RedisCacheConstant;
import com.jiangxjsy.core.exception.BasicException;
import com.jiangxjsy.core.jwt.JwtCore;
import com.jiangxjsy.core.redis.Redis;
import com.jiangxjsy.core.wrap.Result;
import com.jiangxjsy.core.wrap.ResultBuilder;
import com.jiangxjsy.core.wrap.ResultCode;
import com.jiangxjsy.core.wrap.ResultHelper;
import com.jiangxjsy.model.authorization.entity.AuthorizationUser;
import com.jiangxjsy.model.authorization.vo.LoginVO;
import com.jiangxjsy.model.core.entity.UserInfo;
import com.jiangxjsy.model.core.entity.UserMeta;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * wukong-crm-master
 * 蒋胜宇
 * 2025/6/4 14:22
 */

@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    private AdminUserClient adminUserClient;

    @Resource
    private JwtProperty jwtProperty;

    @Resource
    private Redis redis;

    @Resource
    private PermissionSupport permissionSupport;

    @Resource
    private LoginSupport loginSupport;

    /**
     * 权限校验
     *
     * @param authentication 用户权限标识
     * @param url 请求地址
     * @param method 请求方法
     * @return Result
     */
    @Override
    public Result<?> permission(String authentication, String url, String method) {
        UserMeta userMeta = permissionSupport.jwtTokenUserMetaStrict(authentication);
        Long userId = userMeta.getUserId();
        String key = userId.toString();

        List<String> noAuthMenuUrls;
        List<?> noAuthMenuUrlList = redis.get(List.class, key);
        if (noAuthMenuUrlList == null) {
            noAuthMenuUrls = adminUserClient.queryNoAuthMenu(userId).getData();
        } else {
            noAuthMenuUrls = noAuthMenuUrlList.stream()
                    .filter(item -> item instanceof String)
                    .map(item -> (String) item)
                    .collect(Collectors.toList());
        }
        boolean permission = permissionSupport.isHasPermission(noAuthMenuUrls, url);
        Result<Object> result = permission ? ResultBuilder.ok() : ResultBuilder.noAuth();

        if (ResultHelper.hasSuccess(result)) {
            redis.expire(authentication, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
            redis.expire(AdminCacheKey.USER_AUTH_CACHE_KET + key,
                    RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
            redis.expire(CrmCacheKey.CRM_AUTH_USER_CACHE_KEY + key,
                    RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
        }

        return result;
    }

    /**
     * 登录
     *
     * @param user 用户信息
     * @param response 响应
     * @param request 请求
     * @return Result
     */
    @Override
    public Result<?> login(AuthorizationUser user, HttpServletResponse response, HttpServletRequest request) {
        Result<?> result = loginSupport.multipleLoginFailed(user);
        if (ResultHelper.hasFailed(result)) {
            return result;
        }

        UserInfo userInfo = loginSupport.loadUserByUsername(user.getUsername());
        Result<?> ignoreIdentity = loginSupport.validateUserIdentity(user, userInfo);
        Result<?> ignoreStatus = loginSupport.validateUserStatus(user, userInfo);

        UserMeta userMeta = new UserMeta(userInfo.getUserId(), userInfo.getUsername());
        String token;
        try {
            token = new JwtCore<>(UserMeta.class).generateToken(userMeta, jwtProperty.getPrivateKey(), jwtProperty.getExpire());
        } catch (IllegalAccessException ignore) {
            throw new BasicException(ResultCode.SystemResultCode.SYSTEM_ERROR);
        }
        userInfo.setRoles(adminUserClient.queryUserRoleIds(userInfo.getUserId()).getData());

        loginSupport.userExit(userInfo.getUserId(), user.getLoginType(), 1);
        String userToken = loginSupport.getUserToken(user.getLoginType(), userInfo.getUserId());
        redis.setEx(token, userInfo, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);
        redis.setEx(userToken, token, RedisCacheConstant.MAX_CACHE_TIME, TimeUnit.MINUTES);

        Cookie cookie = new Cookie(BasicConstant.TOKEN_NAME, token);
        long second = DateUtil.betweenMs(new Date(), DateUtil.parseDate("2030-01-01")) / 1000L;
        cookie.setMaxAge((int) second);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        response.addCookie(cookie);

        return ResultBuilder.ok().setData(new LoginVO(token));
    }

    /**
     * 注销
     *
     * @param authentication 用户权限标识
     * @return Result
     */
    @Override
    public Result<?> logout(String authentication, HttpServletResponse response, HttpServletRequest request) {
        redis.setEx(RedisCacheConstant.REDIS_BLACK_TOKEN_PREFIX + authentication,
                null,
                jwtProperty.getExpire(),
                TimeUnit.SECONDS
        );

        Object data = redis.get(authentication);
        if (data instanceof UserInfo) {
            UserInfo userInfo = (UserInfo) data;
            redis.delete(authentication);
            redis.delete(AdminCacheKey.USER_AUTH_CACHE_KET + userInfo.getUserId());
            redis.delete(CrmCacheKey.CRM_AUTH_USER_CACHE_KEY + userInfo.getUserId());
        }

        String serverName = StrUtil.isNotEmpty(request.getHeader("proxyHost")) ? request.getHeader("proxyHost") : request.getServerName();
        boolean isIp = serverName.chars().allMatch(c -> c == '.' || (c >= '0' && c <= '9'));
        int index = isIp ? -1 : serverName.indexOf(".");
        String cookieDomain = isIp ? serverName : (index != -1 ? serverName.substring(index) : serverName);
        for (String user : Arrays.asList(BasicConstant.TOKEN_NAME, "User")) {
            Cookie cookie = ServletUtil.getCookie(request, user);
            if (cookie != null) {
                cookie.setMaxAge(0);
                cookie.setValue(null);
                cookie.setPath("/");
                cookie.setDomain(cookieDomain);
                response.addCookie(cookie);
            }
        }
        return ResultBuilder.ok();
    }
}
